package org.boulderfoodrescue.webapp.client.managers;

import java.util.LinkedList;
import java.util.List;

import org.boulderfoodrescue.webapp.client.events.ChangeType;
import org.boulderfoodrescue.webapp.client.events.UserInfoUpdatedEvent;
import org.boulderfoodrescue.webapp.client.events.UserInfoUpdatedHandler;
import org.boulderfoodrescue.webapp.client.events.UsersListUpdatedEvent;
import org.boulderfoodrescue.webapp.client.events.UsersListUpdatedHandler;
import org.boulderfoodrescue.webapp.client.rpc.UserAccountsServiceAsync;
import org.boulderfoodrescue.webapp.shared.LoginInfo;
import org.boulderfoodrescue.webapp.shared.UserAccount;
import org.boulderfoodrescue.webapp.shared.UserAccountDetails;

import com.google.gwt.event.shared.EventBus;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;

public class UserAccountManager {
	private static List<UserAccountDetails> accountUsers;
	private static UserAccount currentUserInfo;
	private static UserAccountsServiceAsync userRPC;
	private static EventBus eventBus;
	public UserAccountManager(UserAccountsServiceAsync userRPC, EventBus eventBus)
	{
		UserAccountManager.userRPC = userRPC;
		UserAccountManager.eventBus = eventBus;
		bind();
	}

	private void bind()
	{
		eventBus.addHandler(UsersListUpdatedEvent.getType(), 
				new UsersListUpdatedHandler(){
			@Override
			public void onUserAdded(UsersListUpdatedEvent event) {
				if(accountUsers == null)
					accountUsers = new LinkedList<UserAccountDetails>();
				accountUsers.add(event.getValue());
			}
			@Override
			public void onUserUpdated(UsersListUpdatedEvent event) {
				// TODO Auto-generated method stub
			}
			@Override
			public void onUserRemoved(UsersListUpdatedEvent event) {
				removeUserAccount(event.getValue());
			}
			@Override
			public void onUserAddFailed(UsersListUpdatedEvent event) {
				// TODO Auto-generated method stub

			}
		});
		eventBus.addHandler(UserInfoUpdatedEvent.getType(),
				new UserInfoUpdatedHandler(){
			@Override
			public void onUserUpdated(UserInfoUpdatedEvent event) {
				currentUserInfo = event.getValue();
				LoginInfo loginInfo = LoginInfoManager.getLoginInfo();
				loginInfo.setFirst_name(currentUserInfo.getFirstName());
				loginInfo.setLast_name(loginInfo.getLast_name());
				loginInfo.setPhone(currentUserInfo.getPhoneNumber());
				UserAccount currentUser = event.getValue();
				for(UserAccountDetails user: accountUsers)
				{
					if(user.getEmail().equals(currentUser.getEmail()))
					{
						user.setFirstName(currentUser.getFirstName());
						user.setLastName(currentUser.getLastName());
						eventBus.fireEvent(new UsersListUpdatedEvent(ChangeType.Updated, user));
						break;
					}
				}
			}
		});
	}

	public static UserAccount getUserAccount()
	{
		if(currentUserInfo != null)
			return currentUserInfo;
		loadUserAccout();
		return null;
	}

	public static List<UserAccountDetails> getAccountUsers()
	{
		if(accountUsers != null)
			return accountUsers;
		loadUserAccountList();
		return null;
	}

	public static void addUser(final UserAccount user)
	{
		userRPC.saveProfileData(user, new AsyncCallback<Long>(){

			@Override
			public void onFailure(Throwable caught) {
				Window.alert("Error connecting to server to save user account");
			}

			@Override
			public void onSuccess(Long result) {
				if(result == null)
					Window.alert("Error saving user account");
				else{
					user.setDatabaseKey(result);
					eventBus.fireEvent(new UsersListUpdatedEvent(ChangeType.Added, user));
				}
			}

		});
	}

	private static void loadUserAccountList()
	{
		userRPC.getListUsers(new AsyncCallback<List<UserAccountDetails>>(){
			@Override
			public void onFailure(Throwable caught) {
				Window.alert("Failed to load list of users. Please check your internet connection");
			}
			@Override
			public void onSuccess(List<UserAccountDetails> result) {
				if(result != null)
				{
					for(UserAccountDetails user : result){
						eventBus.fireEvent(new UsersListUpdatedEvent(ChangeType.Added, user));
					}
				}
				else
					Window.alert("You do not have the rights to access a list of users");
			}
		});
	}

	private void removeUserAccount(final UserAccountDetails user)
	{
		userRPC.removeUser(user, new AsyncCallback<Boolean>(){
			@Override
			public void onFailure(Throwable caught) {
				Window.alert("Failed to delete user from database. Please check your internet connection");
			}
			@Override
			public void onSuccess(Boolean result) {
				if(result)
					accountUsers.remove(user);
				else
					Window.alert("Failed to delete user from database!");
			}
		});
	}

	private static void loadUserAccout()
	{
		userRPC.getUser(new AsyncCallback<UserAccount>(){
			@Override
			public void onFailure(Throwable caught) {
				Window.alert("Failed to load your user info from database. Please check your internet connection");
			}
			@Override
			public void onSuccess(UserAccount result) {
				if(result == null){
					Window.alert("You are not logged in. To load your user info you must first log in.");
				}
				else{
					eventBus.fireEvent(new UserInfoUpdatedEvent(result));
				}
			}
		});
	}

	public static void deleteUser(final UserAccountDetails object) {
		userRPC.removeUser(object, new AsyncCallback<Boolean>(){
			@Override
			public void onFailure(Throwable caught) {
				Window.alert("Unable to delete user from server rpc failure.");
			}

			@Override
			public void onSuccess(Boolean result) {
				if(result){
					eventBus.fireEvent(new UsersListUpdatedEvent(ChangeType.Removed, object));
				}
				else
					Window.alert("Unable to delete user from server.");
			}
		});
	}

	public static void updateUser(final UserAccount user)
	{
		userRPC.saveProfileData(user, new AsyncCallback<Long>(){

			@Override
			public void onFailure(Throwable caught) {
				Window.alert("Error connecting to server to save user account");
			}

			@Override
			public void onSuccess(Long result) {
				if(result == null)
					Window.alert("Error saving user account");
				else{
					user.setDatabaseKey(result);
					eventBus.fireEvent(new UserInfoUpdatedEvent(user));
				}
			}

		});
	}
}
